home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume22 / gawk2.11 / part10 < prev    next >
Encoding:
Internet Message Format  |  1990-06-07  |  54.0 KB

  1. Subject:  v22i096:  GNU AWK, version 2.11, Part10/16
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: d0b66dfc 83c43872 84ece610 c047bb97
  5.  
  6. Submitted-by: "Arnold D. Robbins" <arnold@unix.cc.emory.edu>
  7. Posting-number: Volume 22, Issue 96
  8. Archive-name: gawk2.11/part10
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # Contents:  ./awk.y ./missing.d/memset.c ./missing.d/random.c
  17. #   ./pc.d/popen.h
  18. # Wrapped by rsalz@litchi.bbn.com on Wed Jun  6 12:24:55 1990
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. echo If this archive is complete, you will see the following message:
  21. echo '          "shar: End of archive 10 (of 16)."'
  22. if test -f './awk.y' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'./awk.y'\"
  24. else
  25.   echo shar: Extracting \"'./awk.y'\" \(37017 characters\)
  26.   sed "s/^X//" >'./awk.y' <<'END_OF_FILE'
  27. X/*
  28. X * awk.y --- yacc/bison parser
  29. X */
  30. X
  31. X/* 
  32. X * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
  33. X * 
  34. X * This file is part of GAWK, the GNU implementation of the
  35. X * AWK Progamming Language.
  36. X * 
  37. X * GAWK is free software; you can redistribute it and/or modify
  38. X * it under the terms of the GNU General Public License as published by
  39. X * the Free Software Foundation; either version 1, or (at your option)
  40. X * any later version.
  41. X * 
  42. X * GAWK is distributed in the hope that it will be useful,
  43. X * but WITHOUT ANY WARRANTY; without even the implied warranty of
  44. X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  45. X * GNU General Public License for more details.
  46. X * 
  47. X * You should have received a copy of the GNU General Public License
  48. X * along with GAWK; see the file COPYING.  If not, write to
  49. X * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  50. X */
  51. X
  52. X%{
  53. X#ifdef DEBUG
  54. X#define YYDEBUG 12
  55. X#endif
  56. X
  57. X#include "awk.h"
  58. X
  59. X/*
  60. X * This line is necessary since the Bison parser skeleton uses bcopy.
  61. X * Systems without memcpy should use -DMEMCPY_MISSING, per the Makefile.
  62. X * It should not hurt anything if Yacc is being used instead of Bison.
  63. X */
  64. X#define bcopy(s,d,n)    memcpy((d),(s),(n))
  65. X
  66. Xextern void msg();
  67. Xextern struct re_pattern_buffer *mk_re_parse();
  68. X
  69. XNODE *node();
  70. XNODE *lookup();
  71. XNODE *install();
  72. X
  73. Xstatic NODE *snode();
  74. Xstatic NODE *mkrangenode();
  75. Xstatic FILE *pathopen();
  76. Xstatic NODE *make_for_loop();
  77. Xstatic NODE *append_right();
  78. Xstatic void func_install();
  79. Xstatic NODE *make_param();
  80. Xstatic int hashf();
  81. Xstatic void pop_params();
  82. Xstatic void pop_var();
  83. Xstatic int yylex ();
  84. Xstatic void yyerror();
  85. X
  86. Xstatic int want_regexp;        /* lexical scanning kludge */
  87. Xstatic int want_assign;        /* lexical scanning kludge */
  88. Xstatic int can_return;        /* lexical scanning kludge */
  89. Xstatic int io_allowed = 1;    /* lexical scanning kludge */
  90. Xstatic int lineno = 1;        /* for error msgs */
  91. Xstatic char *lexptr;        /* pointer to next char during parsing */
  92. Xstatic char *lexptr_begin;    /* keep track of where we were for error msgs */
  93. Xstatic int curinfile = -1;    /* index into sourcefiles[] */
  94. Xstatic int param_counter;
  95. X
  96. XNODE *variables[HASHSIZE];
  97. X
  98. Xextern int errcount;
  99. Xextern NODE *begin_block;
  100. Xextern NODE *end_block;
  101. X%}
  102. X
  103. X%union {
  104. X    long lval;
  105. X    AWKNUM fval;
  106. X    NODE *nodeval;
  107. X    NODETYPE nodetypeval;
  108. X    char *sval;
  109. X    NODE *(*ptrval)();
  110. X}
  111. X
  112. X%type <nodeval> function_prologue function_body
  113. X%type <nodeval> rexp exp start program rule simp_exp
  114. X%type <nodeval> pattern 
  115. X%type <nodeval>    action variable param_list
  116. X%type <nodeval>    rexpression_list opt_rexpression_list
  117. X%type <nodeval>    expression_list opt_expression_list
  118. X%type <nodeval>    statements statement if_statement opt_param_list 
  119. X%type <nodeval> opt_exp opt_variable regexp 
  120. X%type <nodeval> input_redir output_redir
  121. X%type <nodetypeval> r_paren comma nls opt_nls print
  122. X
  123. X%type <sval> func_name
  124. X%token <sval> FUNC_CALL NAME REGEXP
  125. X%token <lval> ERROR
  126. X%token <nodeval> NUMBER YSTRING
  127. X%token <nodetypeval> RELOP APPEND_OP
  128. X%token <nodetypeval> ASSIGNOP MATCHOP NEWLINE CONCAT_OP
  129. X%token <nodetypeval> LEX_BEGIN LEX_END LEX_IF LEX_ELSE LEX_RETURN LEX_DELETE
  130. X%token <nodetypeval> LEX_WHILE LEX_DO LEX_FOR LEX_BREAK LEX_CONTINUE
  131. X%token <nodetypeval> LEX_PRINT LEX_PRINTF LEX_NEXT LEX_EXIT LEX_FUNCTION
  132. X%token <nodetypeval> LEX_GETLINE
  133. X%token <nodetypeval> LEX_IN
  134. X%token <lval> LEX_AND LEX_OR INCREMENT DECREMENT
  135. X%token <ptrval> LEX_BUILTIN LEX_LENGTH
  136. X
  137. X/* these are just yylval numbers */
  138. X
  139. X/* Lowest to highest */
  140. X%right ASSIGNOP
  141. X%right '?' ':'
  142. X%left LEX_OR
  143. X%left LEX_AND
  144. X%left LEX_GETLINE
  145. X%nonassoc LEX_IN
  146. X%left FUNC_CALL LEX_BUILTIN LEX_LENGTH
  147. X%nonassoc MATCHOP
  148. X%nonassoc RELOP '<' '>' '|' APPEND_OP
  149. X%left CONCAT_OP
  150. X%left YSTRING NUMBER
  151. X%left '+' '-'
  152. X%left '*' '/' '%'
  153. X%right '!' UNARY
  154. X%right '^'
  155. X%left INCREMENT DECREMENT
  156. X%left '$'
  157. X%left '(' ')'
  158. X
  159. X%%
  160. X
  161. Xstart
  162. X    : opt_nls program opt_nls
  163. X        { expression_value = $2; }
  164. X    ;
  165. X
  166. Xprogram
  167. X    : rule
  168. X        { 
  169. X            if ($1 != NULL)
  170. X                $$ = $1;
  171. X            else
  172. X                $$ = NULL;
  173. X            yyerrok;
  174. X        }
  175. X    | program rule
  176. X        /* add the rule to the tail of list */
  177. X        {
  178. X            if ($2 == NULL)
  179. X                $$ = $1;
  180. X            else if ($1 == NULL)
  181. X                $$ = $2;
  182. X            else {
  183. X                if ($1->type != Node_rule_list)
  184. X                    $1 = node($1, Node_rule_list,
  185. X                        (NODE*)NULL);
  186. X                $$ = append_right ($1,
  187. X                   node($2, Node_rule_list,(NODE *) NULL));
  188. X            }
  189. X            yyerrok;
  190. X        }
  191. X    | error    { $$ = NULL; }
  192. X    | program error { $$ = NULL; }
  193. X    ;
  194. X
  195. Xrule
  196. X    : LEX_BEGIN { io_allowed = 0; }
  197. X      action
  198. X      {
  199. X        if (begin_block) {
  200. X            if (begin_block->type != Node_rule_list)
  201. X                begin_block = node(begin_block, Node_rule_list,
  202. X                    (NODE *)NULL);
  203. X            append_right (begin_block, node(
  204. X                node((NODE *)NULL, Node_rule_node, $3),
  205. X                Node_rule_list, (NODE *)NULL) );
  206. X        } else
  207. X            begin_block = node((NODE *)NULL, Node_rule_node, $3);
  208. X        $$ = NULL;
  209. X        io_allowed = 1;
  210. X        yyerrok;
  211. X      }
  212. X    | LEX_END { io_allowed = 0; }
  213. X      action
  214. X      {
  215. X        if (end_block) {
  216. X            if (end_block->type != Node_rule_list)
  217. X                end_block = node(end_block, Node_rule_list,
  218. X                    (NODE *)NULL);
  219. X            append_right (end_block, node(
  220. X                node((NODE *)NULL, Node_rule_node, $3),
  221. X                Node_rule_list, (NODE *)NULL));
  222. X        } else
  223. X            end_block = node((NODE *)NULL, Node_rule_node, $3);
  224. X        $$ = NULL;
  225. X        io_allowed = 1;
  226. X        yyerrok;
  227. X      }
  228. X    | LEX_BEGIN statement_term
  229. X      {
  230. X        msg ("error near line %d: BEGIN blocks must have an action part", lineno);
  231. X        errcount++;
  232. X        yyerrok;
  233. X      }
  234. X    | LEX_END statement_term
  235. X      {
  236. X        msg ("error near line %d: END blocks must have an action part", lineno);
  237. X        errcount++;
  238. X        yyerrok;
  239. X      }
  240. X    | pattern action
  241. X        { $$ = node ($1, Node_rule_node, $2); yyerrok; }
  242. X    | action
  243. X        { $$ = node ((NODE *)NULL, Node_rule_node, $1); yyerrok; }
  244. X    | pattern statement_term
  245. X        { if($1) $$ = node ($1, Node_rule_node, (NODE *)NULL); yyerrok; }
  246. X    | function_prologue function_body
  247. X        {
  248. X            func_install($1, $2);
  249. X            $$ = NULL;
  250. X            yyerrok;
  251. X        }
  252. X    ;
  253. X
  254. Xfunc_name
  255. X    : NAME
  256. X        { $$ = $1; }
  257. X    | FUNC_CALL
  258. X        { $$ = $1; }
  259. X    ;
  260. X        
  261. Xfunction_prologue
  262. X    : LEX_FUNCTION 
  263. X        {
  264. X            param_counter = 0;
  265. X        }
  266. X      func_name '(' opt_param_list r_paren opt_nls
  267. X        {
  268. X            $$ = append_right(make_param($3), $5);
  269. X            can_return = 1;
  270. X        }
  271. X    ;
  272. X
  273. Xfunction_body
  274. X    : l_brace statements r_brace
  275. X      {
  276. X        $$ = $2;
  277. X        can_return = 0;
  278. X      }
  279. X    ;
  280. X
  281. X
  282. Xpattern
  283. X    : exp
  284. X        { $$ = $1; }
  285. X    | exp comma exp
  286. X        { $$ = mkrangenode ( node($1, Node_cond_pair, $3) ); }
  287. X    ;
  288. X
  289. Xregexp
  290. X    /*
  291. X     * In this rule, want_regexp tells yylex that the next thing
  292. X     * is a regexp so it should read up to the closing slash.
  293. X     */
  294. X    : '/'
  295. X        { ++want_regexp; }
  296. X       REGEXP '/'
  297. X        {
  298. X          want_regexp = 0;
  299. X          $$ = node((NODE *)NULL,Node_regex,(NODE *)mk_re_parse($3, 0));
  300. X          $$ -> re_case = 0;
  301. X          emalloc ($$ -> re_text, char *, strlen($3)+1, "regexp");
  302. X          strcpy ($$ -> re_text, $3);
  303. X        }
  304. X    ;
  305. X
  306. Xaction
  307. X    : l_brace r_brace opt_semi
  308. X        {
  309. X            /* empty actions are different from missing actions */
  310. X            $$ = node ((NODE *) NULL, Node_illegal, (NODE *) NULL);
  311. X        }
  312. X    | l_brace statements r_brace opt_semi
  313. X        { $$ = $2 ; }
  314. X    ;
  315. X
  316. Xstatements
  317. X    : statement
  318. X        { $$ = $1; }
  319. X    | statements statement
  320. X        {
  321. X            if ($1 == NULL || $1->type != Node_statement_list)
  322. X                $1 = node($1, Node_statement_list,(NODE *)NULL);
  323. X                $$ = append_right($1,
  324. X                node( $2, Node_statement_list, (NODE *)NULL));
  325. X                yyerrok;
  326. X        }
  327. X    | error
  328. X        { $$ = NULL; }
  329. X    | statements error
  330. X        { $$ = NULL; }
  331. X    ;
  332. X
  333. Xstatement_term
  334. X    : nls
  335. X        { $<nodetypeval>$ = Node_illegal; }
  336. X    | semi opt_nls
  337. X        { $<nodetypeval>$ = Node_illegal; }
  338. X    ;
  339. X
  340. X    
  341. Xstatement
  342. X    : semi opt_nls
  343. X        { $$ = NULL; }
  344. X    | l_brace r_brace
  345. X        { $$ = NULL; }
  346. X    | l_brace statements r_brace
  347. X        { $$ = $2; }
  348. X    | if_statement
  349. X        { $$ = $1; }
  350. X    | LEX_WHILE '(' exp r_paren opt_nls statement
  351. X        { $$ = node ($3, Node_K_while, $6); }
  352. X    | LEX_DO opt_nls statement LEX_WHILE '(' exp r_paren opt_nls
  353. X        { $$ = node ($6, Node_K_do, $3); }
  354. X    | LEX_FOR '(' NAME LEX_IN NAME r_paren opt_nls statement
  355. X      {
  356. X        $$ = node ($8, Node_K_arrayfor, make_for_loop(variable($3),
  357. X            (NODE *)NULL, variable($5)));
  358. X      }
  359. X    | LEX_FOR '(' opt_exp semi exp semi opt_exp r_paren opt_nls statement
  360. X      {
  361. X        $$ = node($10, Node_K_for, (NODE *)make_for_loop($3, $5, $7));
  362. X      }
  363. X    | LEX_FOR '(' opt_exp semi semi opt_exp r_paren opt_nls statement
  364. X      {
  365. X        $$ = node ($9, Node_K_for,
  366. X            (NODE *)make_for_loop($3, (NODE *)NULL, $6));
  367. X      }
  368. X    | LEX_BREAK statement_term
  369. X       /* for break, maybe we'll have to remember where to break to */
  370. X        { $$ = node ((NODE *)NULL, Node_K_break, (NODE *)NULL); }
  371. X    | LEX_CONTINUE statement_term
  372. X       /* similarly */
  373. X        { $$ = node ((NODE *)NULL, Node_K_continue, (NODE *)NULL); }
  374. X    | print '(' expression_list r_paren output_redir statement_term
  375. X        { $$ = node ($3, $1, $5); }
  376. X    | print opt_rexpression_list output_redir statement_term
  377. X        { $$ = node ($2, $1, $3); }
  378. X    | LEX_NEXT
  379. X        { if (! io_allowed) yyerror("next used in BEGIN or END action"); }
  380. X      statement_term
  381. X        { $$ = node ((NODE *)NULL, Node_K_next, (NODE *)NULL); }
  382. X    | LEX_EXIT opt_exp statement_term
  383. X        { $$ = node ($2, Node_K_exit, (NODE *)NULL); }
  384. X    | LEX_RETURN
  385. X        { if (! can_return) yyerror("return used outside function context"); }
  386. X      opt_exp statement_term
  387. X        { $$ = node ($3, Node_K_return, (NODE *)NULL); }
  388. X    | LEX_DELETE NAME '[' expression_list ']' statement_term
  389. X        { $$ = node (variable($2), Node_K_delete, $4); }
  390. X    | exp statement_term
  391. X        { $$ = $1; }
  392. X    ;
  393. X
  394. Xprint
  395. X    : LEX_PRINT
  396. X        { $$ = $1; }
  397. X    | LEX_PRINTF
  398. X        { $$ = $1; }
  399. X    ;
  400. X
  401. Xif_statement
  402. X    : LEX_IF '(' exp r_paren opt_nls statement
  403. X      {
  404. X        $$ = node($3, Node_K_if, 
  405. X            node($6, Node_if_branches, (NODE *)NULL));
  406. X      }
  407. X    | LEX_IF '(' exp r_paren opt_nls statement
  408. X         LEX_ELSE opt_nls statement
  409. X        { $$ = node ($3, Node_K_if,
  410. X                node ($6, Node_if_branches, $9)); }
  411. X    ;
  412. X
  413. Xnls
  414. X    : NEWLINE
  415. X        { $<nodetypeval>$ = NULL; }
  416. X    | nls NEWLINE
  417. X        { $<nodetypeval>$ = NULL; }
  418. X    ;
  419. X
  420. Xopt_nls
  421. X    : /* empty */
  422. X        { $<nodetypeval>$ = NULL; }
  423. X    | nls
  424. X        { $<nodetypeval>$ = NULL; }
  425. X    ;
  426. X
  427. Xinput_redir
  428. X    : /* empty */
  429. X        { $$ = NULL; }
  430. X    | '<' simp_exp
  431. X        { $$ = node ($2, Node_redirect_input, (NODE *)NULL); }
  432. X    ;
  433. X
  434. Xoutput_redir
  435. X    : /* empty */
  436. X        { $$ = NULL; }
  437. X    | '>' exp
  438. X        { $$ = node ($2, Node_redirect_output, (NODE *)NULL); }
  439. X    | APPEND_OP exp
  440. X        { $$ = node ($2, Node_redirect_append, (NODE *)NULL); }
  441. X    | '|' exp
  442. X        { $$ = node ($2, Node_redirect_pipe, (NODE *)NULL); }
  443. X    ;
  444. X
  445. Xopt_param_list
  446. X    : /* empty */
  447. X        { $$ = NULL; }
  448. X    | param_list
  449. X        { $$ = $1; }
  450. X    ;
  451. X
  452. Xparam_list
  453. X    : NAME
  454. X        { $$ = make_param($1); }
  455. X    | param_list comma NAME
  456. X        { $$ = append_right($1, make_param($3)); yyerrok; }
  457. X    | error
  458. X        { $$ = NULL; }
  459. X    | param_list error
  460. X        { $$ = NULL; }
  461. X    | param_list comma error
  462. X        { $$ = NULL; }
  463. X    ;
  464. X
  465. X/* optional expression, as in for loop */
  466. Xopt_exp
  467. X    : /* empty */
  468. X        { $$ = NULL; }
  469. X    | exp
  470. X        { $$ = $1; }
  471. X    ;
  472. X
  473. Xopt_rexpression_list
  474. X    : /* empty */
  475. X        { $$ = NULL; }
  476. X    | rexpression_list
  477. X        { $$ = $1; }
  478. X    ;
  479. X
  480. Xrexpression_list
  481. X    : rexp
  482. X        { $$ = node ($1, Node_expression_list, (NODE *)NULL); }
  483. X    | rexpression_list comma rexp
  484. X      {
  485. X        $$ = append_right($1,
  486. X            node( $3, Node_expression_list, (NODE *)NULL));
  487. X        yyerrok;
  488. X      }
  489. X    | error
  490. X        { $$ = NULL; }
  491. X    | rexpression_list error
  492. X        { $$ = NULL; }
  493. X    | rexpression_list error rexp
  494. X        { $$ = NULL; }
  495. X    | rexpression_list comma error
  496. X        { $$ = NULL; }
  497. X    ;
  498. X
  499. Xopt_expression_list
  500. X    : /* empty */
  501. X        { $$ = NULL; }
  502. X    | expression_list
  503. X        { $$ = $1; }
  504. X    ;
  505. X
  506. Xexpression_list
  507. X    : exp
  508. X        { $$ = node ($1, Node_expression_list, (NODE *)NULL); }
  509. X    | expression_list comma exp
  510. X        {
  511. X            $$ = append_right($1,
  512. X                node( $3, Node_expression_list, (NODE *)NULL));
  513. X            yyerrok;
  514. X        }
  515. X    | error
  516. X        { $$ = NULL; }
  517. X    | expression_list error
  518. X        { $$ = NULL; }
  519. X    | expression_list error exp
  520. X        { $$ = NULL; }
  521. X    | expression_list comma error
  522. X        { $$ = NULL; }
  523. X    ;
  524. X
  525. X/* Expressions, not including the comma operator.  */
  526. Xexp    : variable ASSIGNOP
  527. X        { want_assign = 0; }
  528. X        exp
  529. X        { $$ = node ($1, $2, $4); }
  530. X    | '(' expression_list r_paren LEX_IN NAME
  531. X        { $$ = node (variable($5), Node_in_array, $2); }
  532. X    | exp '|' LEX_GETLINE opt_variable
  533. X        {
  534. X          $$ = node ($4, Node_K_getline,
  535. X             node ($1, Node_redirect_pipein, (NODE *)NULL));
  536. X        }
  537. X    | LEX_GETLINE opt_variable input_redir
  538. X        {
  539. X          /* "too painful to do right" */
  540. X          /*
  541. X          if (! io_allowed && $3 == NULL)
  542. X            yyerror("non-redirected getline illegal inside BEGIN or END action");
  543. X          */
  544. X          $$ = node ($2, Node_K_getline, $3);
  545. X        }
  546. X    | exp LEX_AND exp
  547. X        { $$ = node ($1, Node_and, $3); }
  548. X    | exp LEX_OR exp
  549. X        { $$ = node ($1, Node_or, $3); }
  550. X    | exp MATCHOP exp
  551. X         { $$ = node ($1, $2, $3); }
  552. X    | regexp
  553. X        { $$ = $1; }
  554. X    | '!' regexp %prec UNARY
  555. X        { $$ = node((NODE *) NULL, Node_nomatch, $2); }
  556. X    | exp LEX_IN NAME
  557. X        { $$ = node (variable($3), Node_in_array, $1); }
  558. X    | exp RELOP exp
  559. X        { $$ = node ($1, $2, $3); }
  560. X    | exp '<' exp
  561. X        { $$ = node ($1, Node_less, $3); }
  562. X    | exp '>' exp
  563. X        { $$ = node ($1, Node_greater, $3); }
  564. X    | exp '?' exp ':' exp
  565. X        { $$ = node($1, Node_cond_exp, node($3, Node_if_branches, $5));}
  566. X    | simp_exp
  567. X        { $$ = $1; }
  568. X    | exp exp %prec CONCAT_OP
  569. X        { $$ = node ($1, Node_concat, $2); }
  570. X    ;
  571. X
  572. Xrexp    
  573. X    : variable ASSIGNOP
  574. X        { want_assign = 0; }
  575. X        rexp
  576. X        { $$ = node ($1, $2, $4); }
  577. X    | rexp LEX_AND rexp
  578. X        { $$ = node ($1, Node_and, $3); }
  579. X    | rexp LEX_OR rexp
  580. X        { $$ = node ($1, Node_or, $3); }
  581. X    | LEX_GETLINE opt_variable input_redir
  582. X        {
  583. X          /* "too painful to do right" */
  584. X          /*
  585. X          if (! io_allowed && $3 == NULL)
  586. X            yyerror("non-redirected getline illegal inside BEGIN or END action");
  587. X          */
  588. X          $$ = node ($2, Node_K_getline, $3);
  589. X        }
  590. X    | regexp
  591. X        { $$ = $1; } 
  592. X    | '!' regexp %prec UNARY
  593. X        { $$ = node((NODE *) NULL, Node_nomatch, $2); }
  594. X    | rexp MATCHOP rexp
  595. X         { $$ = node ($1, $2, $3); }
  596. X    | rexp LEX_IN NAME
  597. X        { $$ = node (variable($3), Node_in_array, $1); }
  598. X    | rexp RELOP rexp
  599. X        { $$ = node ($1, $2, $3); }
  600. X    | rexp '?' rexp ':' rexp
  601. X        { $$ = node($1, Node_cond_exp, node($3, Node_if_branches, $5));}
  602. X    | simp_exp
  603. X        { $$ = $1; }
  604. X    | rexp rexp %prec CONCAT_OP
  605. X        { $$ = node ($1, Node_concat, $2); }
  606. X    ;
  607. X
  608. Xsimp_exp
  609. X    : '!' simp_exp %prec UNARY
  610. X        { $$ = node ($2, Node_not,(NODE *) NULL); }
  611. X    | '(' exp r_paren
  612. X        { $$ = $2; }
  613. X    | LEX_BUILTIN '(' opt_expression_list r_paren
  614. X        { $$ = snode ($3, Node_builtin, $1); }
  615. X    | LEX_LENGTH '(' opt_expression_list r_paren
  616. X        { $$ = snode ($3, Node_builtin, $1); }
  617. X    | LEX_LENGTH
  618. X        { $$ = snode ((NODE *)NULL, Node_builtin, $1); }
  619. X    | FUNC_CALL '(' opt_expression_list r_paren
  620. X      {
  621. X        $$ = node ($3, Node_func_call, make_string($1, strlen($1)));
  622. X      }
  623. X    | INCREMENT variable
  624. X        { $$ = node ($2, Node_preincrement, (NODE *)NULL); }
  625. X    | DECREMENT variable
  626. X        { $$ = node ($2, Node_predecrement, (NODE *)NULL); }
  627. X    | variable INCREMENT
  628. X        { $$ = node ($1, Node_postincrement, (NODE *)NULL); }
  629. X    | variable DECREMENT
  630. X        { $$ = node ($1, Node_postdecrement, (NODE *)NULL); }
  631. X    | variable
  632. X        { $$ = $1; }
  633. X    | NUMBER
  634. X        { $$ = $1; }
  635. X    | YSTRING
  636. X        { $$ = $1; }
  637. X
  638. X    /* Binary operators in order of decreasing precedence.  */
  639. X    | simp_exp '^' simp_exp
  640. X        { $$ = node ($1, Node_exp, $3); }
  641. X    | simp_exp '*' simp_exp
  642. X        { $$ = node ($1, Node_times, $3); }
  643. X    | simp_exp '/' simp_exp
  644. X        { $$ = node ($1, Node_quotient, $3); }
  645. X    | simp_exp '%' simp_exp
  646. X        { $$ = node ($1, Node_mod, $3); }
  647. X    | simp_exp '+' simp_exp
  648. X        { $$ = node ($1, Node_plus, $3); }
  649. X    | simp_exp '-' simp_exp
  650. X        { $$ = node ($1, Node_minus, $3); }
  651. X    | '-' simp_exp    %prec UNARY
  652. X        { $$ = node ($2, Node_unary_minus, (NODE *)NULL); }
  653. X    | '+' simp_exp    %prec UNARY
  654. X        { $$ = $2; }
  655. X    ;
  656. X
  657. Xopt_variable
  658. X    : /* empty */
  659. X        { $$ = NULL; }
  660. X    | variable
  661. X        { $$ = $1; }
  662. X    ;
  663. X
  664. Xvariable
  665. X    : NAME
  666. X        { want_assign = 1; $$ = variable ($1); }
  667. X    | NAME '[' expression_list ']'
  668. X        { want_assign = 1; $$ = node (variable($1), Node_subscript, $3); }
  669. X    | '$' simp_exp
  670. X        { want_assign = 1; $$ = node ($2, Node_field_spec, (NODE *)NULL); }
  671. X    ;
  672. X
  673. Xl_brace
  674. X    : '{' opt_nls
  675. X    ;
  676. X
  677. Xr_brace
  678. X    : '}' opt_nls    { yyerrok; }
  679. X    ;
  680. X
  681. Xr_paren
  682. X    : ')' { $<nodetypeval>$ = Node_illegal; yyerrok; }
  683. X    ;
  684. X
  685. Xopt_semi
  686. X    : /* empty */
  687. X    | semi
  688. X    ;
  689. X
  690. Xsemi
  691. X    : ';'    { yyerrok; }
  692. X    ;
  693. X
  694. Xcomma    : ',' opt_nls    { $<nodetypeval>$ = Node_illegal; yyerrok; }
  695. X    ;
  696. X
  697. X%%
  698. X
  699. Xstruct token {
  700. X    char *operator;        /* text to match */
  701. X    NODETYPE value;        /* node type */
  702. X    int class;        /* lexical class */
  703. X    short nostrict;        /* ignore if in strict compatibility mode */
  704. X    NODE *(*ptr) ();    /* function that implements this keyword */
  705. X};
  706. X
  707. Xextern NODE
  708. X    *do_exp(),    *do_getline(),    *do_index(),    *do_length(),
  709. X    *do_sqrt(),    *do_log(),    *do_sprintf(),    *do_substr(),
  710. X    *do_split(),    *do_system(),    *do_int(),    *do_close(),
  711. X    *do_atan2(),    *do_sin(),    *do_cos(),    *do_rand(),
  712. X    *do_srand(),    *do_match(),    *do_tolower(),    *do_toupper(),
  713. X    *do_sub(),    *do_gsub();
  714. X
  715. X/* Special functions for debugging */
  716. X#ifdef DEBUG
  717. XNODE *do_prvars(), *do_bp();
  718. X#endif
  719. X
  720. X/* Tokentab is sorted ascii ascending order, so it can be binary searched. */
  721. X
  722. Xstatic struct token tokentab[] = {
  723. X    { "BEGIN",    Node_illegal,        LEX_BEGIN,    0,    0 },
  724. X    { "END",    Node_illegal,        LEX_END,    0,    0 },
  725. X    { "atan2",    Node_builtin,        LEX_BUILTIN,    0,    do_atan2 },
  726. X#ifdef DEBUG
  727. X    { "bp",        Node_builtin,        LEX_BUILTIN,    0,    do_bp },
  728. X#endif
  729. X    { "break",    Node_K_break,        LEX_BREAK,    0,    0 },
  730. X    { "close",    Node_builtin,        LEX_BUILTIN,    0,    do_close },
  731. X    { "continue",    Node_K_continue,    LEX_CONTINUE,    0,    0 },
  732. X    { "cos",    Node_builtin,        LEX_BUILTIN,    0,    do_cos },
  733. X    { "delete",    Node_K_delete,        LEX_DELETE,    0,    0 },
  734. X    { "do",        Node_K_do,        LEX_DO,        0,    0 },
  735. X    { "else",    Node_illegal,        LEX_ELSE,    0,    0 },
  736. X    { "exit",    Node_K_exit,        LEX_EXIT,    0,    0 },
  737. X    { "exp",    Node_builtin,        LEX_BUILTIN,    0,    do_exp },
  738. X    { "for",    Node_K_for,        LEX_FOR,    0,    0 },
  739. X    { "func",    Node_K_function,    LEX_FUNCTION,    0,    0 },
  740. X    { "function",    Node_K_function,    LEX_FUNCTION,    0,    0 },
  741. X    { "getline",    Node_K_getline,        LEX_GETLINE,    0,    0 },
  742. X    { "gsub",    Node_builtin,        LEX_BUILTIN,    0,    do_gsub },
  743. X    { "if",        Node_K_if,        LEX_IF,        0,    0 },
  744. X    { "in",        Node_illegal,        LEX_IN,        0,    0 },
  745. X    { "index",    Node_builtin,        LEX_BUILTIN,    0,    do_index },
  746. X    { "int",    Node_builtin,        LEX_BUILTIN,    0,    do_int },
  747. X    { "length",    Node_builtin,        LEX_LENGTH,    0,    do_length },
  748. X    { "log",    Node_builtin,        LEX_BUILTIN,    0,    do_log },
  749. X    { "match",    Node_builtin,        LEX_BUILTIN,    0,    do_match },
  750. X    { "next",    Node_K_next,        LEX_NEXT,    0,    0 },
  751. X    { "print",    Node_K_print,        LEX_PRINT,    0,    0 },
  752. X    { "printf",    Node_K_printf,        LEX_PRINTF,    0,    0 },
  753. X#ifdef DEBUG
  754. X    { "prvars",    Node_builtin,        LEX_BUILTIN,    0,    do_prvars },
  755. X#endif
  756. X    { "rand",    Node_builtin,        LEX_BUILTIN,    0,    do_rand },
  757. X    { "return",    Node_K_return,        LEX_RETURN,    0,    0 },
  758. X    { "sin",    Node_builtin,        LEX_BUILTIN,    0,    do_sin },
  759. X    { "split",    Node_builtin,        LEX_BUILTIN,    0,    do_split },
  760. X    { "sprintf",    Node_builtin,        LEX_BUILTIN,    0,    do_sprintf },
  761. X    { "sqrt",    Node_builtin,        LEX_BUILTIN,    0,    do_sqrt },
  762. X    { "srand",    Node_builtin,        LEX_BUILTIN,    0,    do_srand },
  763. X    { "sub",    Node_builtin,        LEX_BUILTIN,    0,    do_sub },
  764. X    { "substr",    Node_builtin,        LEX_BUILTIN,    0,    do_substr },
  765. X    { "system",    Node_builtin,        LEX_BUILTIN,    0,    do_system },
  766. X    { "tolower",    Node_builtin,        LEX_BUILTIN,    0,    do_tolower },
  767. X    { "toupper",    Node_builtin,        LEX_BUILTIN,    0,    do_toupper },
  768. X    { "while",    Node_K_while,        LEX_WHILE,    0,    0 },
  769. X};
  770. X
  771. Xstatic char *token_start;
  772. X
  773. X/* VARARGS0 */
  774. Xstatic void
  775. Xyyerror(va_alist)
  776. Xva_dcl
  777. X{
  778. X    va_list args;
  779. X    char *mesg;
  780. X    register char *ptr, *beg;
  781. X    char *scan;
  782. X
  783. X    errcount++;
  784. X    /* Find the current line in the input file */
  785. X    if (! lexptr) {
  786. X        beg = "(END OF FILE)";
  787. X        ptr = beg + 13;
  788. X    } else {
  789. X        if (*lexptr == '\n' && lexptr != lexptr_begin)
  790. X            --lexptr;
  791. X        for (beg = lexptr; beg != lexptr_begin && *beg != '\n'; --beg)
  792. X            ;
  793. X        /* NL isn't guaranteed */
  794. X        for (ptr = lexptr; *ptr && *ptr != '\n'; ptr++)
  795. X            ;
  796. X        if (beg != lexptr_begin)
  797. X            beg++;
  798. X    }
  799. X    msg("syntax error near line %d:\n%.*s", lineno, ptr - beg, beg);
  800. X    scan = beg;
  801. X    while (scan < token_start)
  802. X        if (*scan++ == '\t')
  803. X            putc('\t', stderr);
  804. X        else
  805. X            putc(' ', stderr);
  806. X    putc('^', stderr);
  807. X    putc(' ', stderr);
  808. X    va_start(args);
  809. X    mesg = va_arg(args, char *);
  810. X    vfprintf(stderr, mesg, args);
  811. X    va_end(args);
  812. X    putc('\n', stderr);
  813. X    exit(1);
  814. X}
  815. X
  816. X/*
  817. X * Parse a C escape sequence.  STRING_PTR points to a variable containing a
  818. X * pointer to the string to parse.  That pointer is updated past the
  819. X * characters we use.  The value of the escape sequence is returned. 
  820. X *
  821. X * A negative value means the sequence \ newline was seen, which is supposed to
  822. X * be equivalent to nothing at all. 
  823. X *
  824. X * If \ is followed by a null character, we return a negative value and leave
  825. X * the string pointer pointing at the null character. 
  826. X *
  827. X * If \ is followed by 000, we return 0 and leave the string pointer after the
  828. X * zeros.  A value of 0 does not mean end of string.  
  829. X */
  830. X
  831. Xint
  832. Xparse_escape(string_ptr)
  833. Xchar **string_ptr;
  834. X{
  835. X    register int c = *(*string_ptr)++;
  836. X    register int i;
  837. X    register int count;
  838. X
  839. X    switch (c) {
  840. X    case 'a':
  841. X        return BELL;
  842. X    case 'b':
  843. X        return '\b';
  844. X    case 'f':
  845. X        return '\f';
  846. X    case 'n':
  847. X        return '\n';
  848. X    case 'r':
  849. X        return '\r';
  850. X    case 't':
  851. X        return '\t';
  852. X    case 'v':
  853. X        return '\v';
  854. X    case '\n':
  855. X        return -2;
  856. X    case 0:
  857. X        (*string_ptr)--;
  858. X        return -1;
  859. X    case '0':
  860. X    case '1':
  861. X    case '2':
  862. X    case '3':
  863. X    case '4':
  864. X    case '5':
  865. X    case '6':
  866. X    case '7':
  867. X        i = c - '0';
  868. X        count = 0;
  869. X        while (++count < 3) {
  870. X            if ((c = *(*string_ptr)++) >= '0' && c <= '7') {
  871. X                i *= 8;
  872. X                i += c - '0';
  873. X            } else {
  874. X                (*string_ptr)--;
  875. X                break;
  876. X            }
  877. X        }
  878. X        return i;
  879. X    case 'x':
  880. X        i = 0;
  881. X        while (1) {
  882. X            if (isxdigit((c = *(*string_ptr)++))) {
  883. X                if (isdigit(c))
  884. X                    i += c - '0';
  885. X                else if (isupper(c))
  886. X                    i += c - 'A' + 10;
  887. X                else
  888. X                    i += c - 'a' + 10;
  889. X            } else {
  890. X                (*string_ptr)--;
  891. X                break;
  892. X            }
  893. X        }
  894. X        return i;
  895. X    default:
  896. X        return c;
  897. X    }
  898. X}
  899. X
  900. X/*
  901. X * Read the input and turn it into tokens. Input is now read from a file
  902. X * instead of from malloc'ed memory. The main program takes a program
  903. X * passed as a command line argument and writes it to a temp file. Otherwise
  904. X * the file name is made available in an external variable.
  905. X */
  906. X
  907. Xstatic int
  908. Xyylex()
  909. X{
  910. X    register int c;
  911. X    register int namelen;
  912. X    register char *tokstart;
  913. X    char *tokkey;
  914. X    static did_newline = 0;    /* the grammar insists that actions end
  915. X                 * with newlines.  This was easier than
  916. X                 * hacking the grammar. */
  917. X    int seen_e = 0;        /* These are for numbers */
  918. X    int seen_point = 0;
  919. X    int esc_seen;
  920. X    extern char **sourcefile;
  921. X    extern int tempsource, numfiles;
  922. X    static int file_opened = 0;
  923. X    static FILE *fin;
  924. X    static char cbuf[BUFSIZ];
  925. X    int low, mid, high;
  926. X#ifdef DEBUG
  927. X    extern int debugging;
  928. X#endif
  929. X
  930. X    if (! file_opened) {
  931. X        file_opened = 1;
  932. X#ifdef DEBUG
  933. X        if (debugging) {
  934. X            int i;
  935. X
  936. X            for (i = 0; i <= numfiles; i++)
  937. X                fprintf (stderr, "sourcefile[%d] = %s\n", i,
  938. X                        sourcefile[i]);
  939. X        }
  940. X#endif
  941. X    nextfile:
  942. X        if ((fin = pathopen (sourcefile[++curinfile])) == NULL)
  943. X            fatal("cannot open `%s' for reading (%s)",
  944. X                sourcefile[curinfile],
  945. X                strerror(errno));
  946. X        *(lexptr = cbuf) = '\0';
  947. X        /*
  948. X         * immediately unlink the tempfile so that it will
  949. X         * go away cleanly if we bomb.
  950. X         */
  951. X        if (tempsource && curinfile == 0)
  952. X            (void) unlink (sourcefile[curinfile]);
  953. X    }
  954. X
  955. Xretry:
  956. X    if (! *lexptr)
  957. X        if (fgets (cbuf, sizeof cbuf, fin) == NULL) {
  958. X            if (fin != NULL)
  959. X                fclose (fin);    /* be neat and clean */
  960. X            if (curinfile < numfiles)
  961. X                goto nextfile;
  962. X            return 0;
  963. X        } else
  964. X            lexptr = lexptr_begin = cbuf;
  965. X
  966. X    if (want_regexp) {
  967. X        int in_brack = 0;
  968. X
  969. X        want_regexp = 0;
  970. X        token_start = tokstart = lexptr;
  971. X        while (c = *lexptr++) {
  972. X            switch (c) {
  973. X            case '[':
  974. X                in_brack = 1;
  975. X                break;
  976. X            case ']':
  977. X                in_brack = 0;
  978. X                break;
  979. X            case '\\':
  980. X                if (*lexptr++ == '\0') {
  981. X                    yyerror("unterminated regexp ends with \\");
  982. X                    return ERROR;
  983. X                } else if (lexptr[-1] == '\n')
  984. X                    goto retry;
  985. X                break;
  986. X            case '/':    /* end of the regexp */
  987. X                if (in_brack)
  988. X                    break;
  989. X
  990. X                lexptr--;
  991. X                yylval.sval = tokstart;
  992. X                return REGEXP;
  993. X            case '\n':
  994. X                lineno++;
  995. X            case '\0':
  996. X                lexptr--;    /* so error messages work */
  997. X                yyerror("unterminated regexp");
  998. X                return ERROR;
  999. X            }
  1000. X        }
  1001. X    }
  1002. X
  1003. X    if (*lexptr == '\n') {
  1004. X        lexptr++;
  1005. X        lineno++;
  1006. X        return NEWLINE;
  1007. X    }
  1008. X
  1009. X    while (*lexptr == ' ' || *lexptr == '\t')
  1010. X        lexptr++;
  1011. X
  1012. X    token_start = tokstart = lexptr;
  1013. X
  1014. X    switch (c = *lexptr++) {
  1015. X    case 0:
  1016. X        return 0;
  1017. X
  1018. X    case '\n':
  1019. X        lineno++;
  1020. X        return NEWLINE;
  1021. X
  1022. X    case '#':        /* it's a comment */
  1023. X        while (*lexptr != '\n' && *lexptr != '\0')
  1024. X            lexptr++;
  1025. X        goto retry;
  1026. X
  1027. X    case '\\':
  1028. X        if (*lexptr == '\n') {
  1029. X            lineno++;
  1030. X            lexptr++;
  1031. X            goto retry;
  1032. X        } else
  1033. X            break;
  1034. X    case ')':
  1035. X    case ']':
  1036. X    case '(':    
  1037. X    case '[':
  1038. X    case '$':
  1039. X    case ';':
  1040. X    case ':':
  1041. X    case '?':
  1042. X
  1043. X        /*
  1044. X         * set node type to ILLEGAL because the action should set it
  1045. X         * to the right thing 
  1046. X         */
  1047. X        yylval.nodetypeval = Node_illegal;
  1048. X        return c;
  1049. X
  1050. X    case '{':
  1051. X    case ',':
  1052. X        yylval.nodetypeval = Node_illegal;
  1053. X        return c;
  1054. X
  1055. X    case '*':
  1056. X        if (*lexptr == '=') {
  1057. X            yylval.nodetypeval = Node_assign_times;
  1058. X            lexptr++;
  1059. X            return ASSIGNOP;
  1060. X        } else if (*lexptr == '*') {    /* make ** and **= aliases
  1061. X                         * for ^ and ^= */
  1062. X            if (lexptr[1] == '=') {
  1063. X                yylval.nodetypeval = Node_assign_exp;
  1064. X                lexptr += 2;
  1065. X                return ASSIGNOP;
  1066. X            } else {
  1067. X                yylval.nodetypeval = Node_illegal;
  1068. X                lexptr++;
  1069. X                return '^';
  1070. X            }
  1071. X        }
  1072. X        yylval.nodetypeval = Node_illegal;
  1073. X        return c;
  1074. X
  1075. X    case '/':
  1076. X        if (want_assign && *lexptr == '=') {
  1077. X            yylval.nodetypeval = Node_assign_quotient;
  1078. X            lexptr++;
  1079. X            return ASSIGNOP;
  1080. X        }
  1081. X        yylval.nodetypeval = Node_illegal;
  1082. X        return c;
  1083. X
  1084. X    case '%':
  1085. X        if (*lexptr == '=') {
  1086. X            yylval.nodetypeval = Node_assign_mod;
  1087. X            lexptr++;
  1088. X            return ASSIGNOP;
  1089. X        }
  1090. X        yylval.nodetypeval = Node_illegal;
  1091. X        return c;
  1092. X
  1093. X    case '^':
  1094. X        if (*lexptr == '=') {
  1095. X            yylval.nodetypeval = Node_assign_exp;
  1096. X            lexptr++;
  1097. X            return ASSIGNOP;
  1098. X        }
  1099. X        yylval.nodetypeval = Node_illegal;
  1100. X        return c;
  1101. X
  1102. X    case '+':
  1103. X        if (*lexptr == '=') {
  1104. X            yylval.nodetypeval = Node_assign_plus;
  1105. X            lexptr++;
  1106. X            return ASSIGNOP;
  1107. X        }
  1108. X        if (*lexptr == '+') {
  1109. X            yylval.nodetypeval = Node_illegal;
  1110. X            lexptr++;
  1111. X            return INCREMENT;
  1112. X        }
  1113. X        yylval.nodetypeval = Node_illegal;
  1114. X        return c;
  1115. X
  1116. X    case '!':
  1117. X        if (*lexptr == '=') {
  1118. X            yylval.nodetypeval = Node_notequal;
  1119. X            lexptr++;
  1120. X            return RELOP;
  1121. X        }
  1122. X        if (*lexptr == '~') {
  1123. X            yylval.nodetypeval = Node_nomatch;
  1124. X            lexptr++;
  1125. X            return MATCHOP;
  1126. X        }
  1127. X        yylval.nodetypeval = Node_illegal;
  1128. X        return c;
  1129. X
  1130. X    case '<':
  1131. X        if (*lexptr == '=') {
  1132. X            yylval.nodetypeval = Node_leq;
  1133. X            lexptr++;
  1134. X            return RELOP;
  1135. X        }
  1136. X        yylval.nodetypeval = Node_less;
  1137. X        return c;
  1138. X
  1139. X    case '=':
  1140. X        if (*lexptr == '=') {
  1141. X            yylval.nodetypeval = Node_equal;
  1142. X            lexptr++;
  1143. X            return RELOP;
  1144. X        }
  1145. X        yylval.nodetypeval = Node_assign;
  1146. X        return ASSIGNOP;
  1147. X
  1148. X    case '>':
  1149. X        if (*lexptr == '=') {
  1150. X            yylval.nodetypeval = Node_geq;
  1151. X            lexptr++;
  1152. X            return RELOP;
  1153. X        } else if (*lexptr == '>') {
  1154. X            yylval.nodetypeval = Node_redirect_append;
  1155. X            lexptr++;
  1156. X            return APPEND_OP;
  1157. X        }
  1158. X        yylval.nodetypeval = Node_greater;
  1159. X        return c;
  1160. X
  1161. X    case '~':
  1162. X        yylval.nodetypeval = Node_match;
  1163. X        return MATCHOP;
  1164. X
  1165. X    case '}':
  1166. X        /*
  1167. X         * Added did newline stuff.  Easier than
  1168. X         * hacking the grammar
  1169. X         */
  1170. X        if (did_newline) {
  1171. X            did_newline = 0;
  1172. X            return c;
  1173. X        }
  1174. X        did_newline++;
  1175. X        --lexptr;
  1176. X        return NEWLINE;
  1177. X
  1178. X    case '"':
  1179. X        esc_seen = 0;
  1180. X        while (*lexptr != '\0') {
  1181. X            switch (*lexptr++) {
  1182. X            case '\\':
  1183. X                esc_seen = 1;
  1184. X                if (*lexptr == '\n')
  1185. X                    yyerror("newline in string");
  1186. X                if (*lexptr++ != '\0')
  1187. X                    break;
  1188. X                /* fall through */
  1189. X            case '\n':
  1190. X                lexptr--;
  1191. X                yyerror("unterminated string");
  1192. X                return ERROR;
  1193. X            case '"':
  1194. X                yylval.nodeval = make_str_node(tokstart + 1,
  1195. X                        lexptr-tokstart-2, esc_seen);
  1196. X                yylval.nodeval->flags |= PERM;
  1197. X                return YSTRING;
  1198. X            }
  1199. X        }
  1200. X        return ERROR;
  1201. X
  1202. X    case '-':
  1203. X        if (*lexptr == '=') {
  1204. X            yylval.nodetypeval = Node_assign_minus;
  1205. X            lexptr++;
  1206. X            return ASSIGNOP;
  1207. X        }
  1208. X        if (*lexptr == '-') {
  1209. X            yylval.nodetypeval = Node_illegal;
  1210. X            lexptr++;
  1211. X            return DECREMENT;
  1212. X        }
  1213. X        yylval.nodetypeval = Node_illegal;
  1214. X        return c;
  1215. X
  1216. X    case '0':
  1217. X    case '1':
  1218. X    case '2':
  1219. X    case '3':
  1220. X    case '4':
  1221. X    case '5':
  1222. X    case '6':
  1223. X    case '7':
  1224. X    case '8':
  1225. X    case '9':
  1226. X    case '.':
  1227. X        /* It's a number */
  1228. X        for (namelen = 0; (c = tokstart[namelen]) != '\0'; namelen++) {
  1229. X            switch (c) {
  1230. X            case '.':
  1231. X                if (seen_point)
  1232. X                    goto got_number;
  1233. X                ++seen_point;
  1234. X                break;
  1235. X            case 'e':
  1236. X            case 'E':
  1237. X                if (seen_e)
  1238. X                    goto got_number;
  1239. X                ++seen_e;
  1240. X                if (tokstart[namelen + 1] == '-' ||
  1241. X                    tokstart[namelen + 1] == '+')
  1242. X                    namelen++;
  1243. X                break;
  1244. X            case '0':
  1245. X            case '1':
  1246. X            case '2':
  1247. X            case '3':
  1248. X            case '4':
  1249. X            case '5':
  1250. X            case '6':
  1251. X            case '7':
  1252. X            case '8':
  1253. X            case '9':
  1254. X                break;
  1255. X            default:
  1256. X                goto got_number;
  1257. X            }
  1258. X        }
  1259. X
  1260. Xgot_number:
  1261. X        lexptr = tokstart + namelen;
  1262. X        /*
  1263. X        yylval.nodeval = make_string(tokstart, namelen);
  1264. X        (void) force_number(yylval.nodeval);
  1265. X        */
  1266. X        yylval.nodeval = make_number(atof(tokstart));
  1267. X        yylval.nodeval->flags |= PERM;
  1268. X        return NUMBER;
  1269. X
  1270. X    case '&':
  1271. X        if (*lexptr == '&') {
  1272. X            yylval.nodetypeval = Node_and;
  1273. X            while (c = *++lexptr) {
  1274. X                if (c == '#')
  1275. X                    while ((c = *++lexptr) != '\n'
  1276. X                           && c != '\0')
  1277. X                        ;
  1278. X                if (c == '\n')
  1279. X                    lineno++;
  1280. X                else if (! isspace(c))
  1281. X                    break;
  1282. X            }
  1283. X            return LEX_AND;
  1284. X        }
  1285. X        return ERROR;
  1286. X
  1287. X    case '|':
  1288. X        if (*lexptr == '|') {
  1289. X            yylval.nodetypeval = Node_or;
  1290. X            while (c = *++lexptr) {
  1291. X                if (c == '#')
  1292. X                    while ((c = *++lexptr) != '\n'
  1293. X                           && c != '\0')
  1294. X                        ;
  1295. X                if (c == '\n')
  1296. X                    lineno++;
  1297. X                else if (! isspace(c))
  1298. X                    break;
  1299. X            }
  1300. X            return LEX_OR;
  1301. X        }
  1302. X        yylval.nodetypeval = Node_illegal;
  1303. X        return c;
  1304. X    }
  1305. X
  1306. X    if (c != '_' && ! isalpha(c)) {
  1307. X        yyerror("Invalid char '%c' in expression\n", c);
  1308. X        return ERROR;
  1309. X    }
  1310. X
  1311. X    /* it's some type of name-type-thing.  Find its length */
  1312. X    for (namelen = 0; is_identchar(tokstart[namelen]); namelen++)
  1313. X        /* null */ ;
  1314. X    emalloc(tokkey, char *, namelen+1, "yylex");
  1315. X    memcpy(tokkey, tokstart, namelen);
  1316. X    tokkey[namelen] = '\0';
  1317. X
  1318. X    /* See if it is a special token.  */
  1319. X    low = 0;
  1320. X    high = (sizeof (tokentab) / sizeof (tokentab[0])) - 1;
  1321. X    while (low <= high) {
  1322. X        int i, c;
  1323. X
  1324. X        mid = (low + high) / 2;
  1325. X        c = *tokstart - tokentab[mid].operator[0];
  1326. X        i = c ? c : strcmp (tokkey, tokentab[mid].operator);
  1327. X
  1328. X        if (i < 0) {        /* token < mid */
  1329. X            high = mid - 1;
  1330. X        } else if (i > 0) {    /* token > mid */
  1331. X            low = mid + 1;
  1332. X        } else {
  1333. X            lexptr = tokstart + namelen;
  1334. X            if (strict && tokentab[mid].nostrict)
  1335. X                break;
  1336. X            if (tokentab[mid].class == LEX_BUILTIN
  1337. X                || tokentab[mid].class == LEX_LENGTH)
  1338. X                yylval.ptrval = tokentab[mid].ptr;
  1339. X            else
  1340. X                yylval.nodetypeval = tokentab[mid].value;
  1341. X            return tokentab[mid].class;
  1342. X        }
  1343. X    }
  1344. X
  1345. X    /* It's a name.  See how long it is.  */
  1346. X    yylval.sval = tokkey;
  1347. X    lexptr = tokstart + namelen;
  1348. X    if (*lexptr == '(')
  1349. X        return FUNC_CALL;
  1350. X    else
  1351. X        return NAME;
  1352. X}
  1353. X
  1354. X#ifndef DEFPATH
  1355. X#ifdef MSDOS
  1356. X#define DEFPATH    "."
  1357. X#define ENVSEP    ';'
  1358. X#else
  1359. X#define DEFPATH    ".:/usr/lib/awk:/usr/local/lib/awk"
  1360. X#define ENVSEP    ':'
  1361. X#endif
  1362. X#endif
  1363. X
  1364. Xstatic FILE *
  1365. Xpathopen (file)
  1366. Xchar *file;
  1367. X{
  1368. X    static char *savepath = DEFPATH;
  1369. X    static int first = 1;
  1370. X    char *awkpath, *cp;
  1371. X    char trypath[BUFSIZ];
  1372. X    FILE *fp;
  1373. X#ifdef DEBUG
  1374. X    extern int debugging;
  1375. X#endif
  1376. X    int fd;
  1377. X
  1378. X    if (strcmp (file, "-") == 0)
  1379. X        return (stdin);
  1380. X
  1381. X    if (strict)
  1382. X        return (fopen (file, "r"));
  1383. X
  1384. X    if (first) {
  1385. X        first = 0;
  1386. X        if ((awkpath = getenv ("AWKPATH")) != NULL && *awkpath)
  1387. X            savepath = awkpath;    /* used for restarting */
  1388. X    }
  1389. X    awkpath = savepath;
  1390. X
  1391. X    /* some kind of path name, no search */
  1392. X#ifndef MSDOS
  1393. X    if (strchr (file, '/') != NULL)
  1394. X#else
  1395. X    if (strchr (file, '/') != NULL || strchr (file, '\\') != NULL
  1396. X            || strchr (file, ':') != NULL)
  1397. X#endif
  1398. X        return ( (fd = devopen (file, "r")) >= 0 ?
  1399. X                fdopen(fd, "r") :
  1400. X                NULL);
  1401. X
  1402. X    do {
  1403. X        trypath[0] = '\0';
  1404. X        /* this should take into account limits on size of trypath */
  1405. X        for (cp = trypath; *awkpath && *awkpath != ENVSEP; )
  1406. X            *cp++ = *awkpath++;
  1407. X
  1408. X        if (cp != trypath) {    /* nun-null element in path */
  1409. X            *cp++ = '/';
  1410. X            strcpy (cp, file);
  1411. X        } else
  1412. X            strcpy (trypath, file);
  1413. X#ifdef DEBUG
  1414. X        if (debugging)
  1415. X            fprintf(stderr, "trying: %s\n", trypath);
  1416. X#endif
  1417. X        if ((fd = devopen (trypath, "r")) >= 0
  1418. X            && (fp = fdopen(fd, "r")) != NULL)
  1419. X            return (fp);
  1420. X
  1421. X        /* no luck, keep going */
  1422. X        if(*awkpath == ENVSEP && awkpath[1] != '\0')
  1423. X            awkpath++;    /* skip colon */
  1424. X    } while (*awkpath);
  1425. X#ifdef MSDOS
  1426. X    /*
  1427. X     * Under DOS (and probably elsewhere) you might have one of the awk
  1428. X     * paths defined, WITHOUT the current working directory in it.
  1429. X     * Therefore you should try to open the file in the current directory.
  1430. X     */
  1431. X    return ( (fd = devopen(file, "r")) >= 0 ? fdopen(fd, "r") : NULL);
  1432. X#else
  1433. X    return (NULL);
  1434. X#endif
  1435. X}
  1436. X
  1437. Xstatic NODE *
  1438. Xnode_common(op)
  1439. XNODETYPE op;
  1440. X{
  1441. X    register NODE *r;
  1442. X    extern int numfiles;
  1443. X    extern int tempsource;
  1444. X    extern char **sourcefile;
  1445. X
  1446. X    r = newnode(op);
  1447. X    r->source_line = lineno;
  1448. X    if (numfiles > -1 && ! tempsource)
  1449. X        r->source_file = sourcefile[curinfile];
  1450. X    else
  1451. X        r->source_file = NULL;
  1452. X    return r;
  1453. X}
  1454. X
  1455. X/*
  1456. X * This allocates a node with defined lnode and rnode. 
  1457. X * This should only be used by yyparse+co while reading in the program 
  1458. X */
  1459. XNODE *
  1460. Xnode(left, op, right)
  1461. XNODE *left, *right;
  1462. XNODETYPE op;
  1463. X{
  1464. X    register NODE *r;
  1465. X
  1466. X    r = node_common(op);
  1467. X    r->lnode = left;
  1468. X    r->rnode = right;
  1469. X    return r;
  1470. X}
  1471. X
  1472. X/*
  1473. X * This allocates a node with defined subnode and proc
  1474. X * Otherwise like node()
  1475. X */
  1476. Xstatic NODE *
  1477. Xsnode(subn, op, procp)
  1478. XNODETYPE op;
  1479. XNODE *(*procp) ();
  1480. XNODE *subn;
  1481. X{
  1482. X    register NODE *r;
  1483. X
  1484. X    r = node_common(op);
  1485. X    r->subnode = subn;
  1486. X    r->proc = procp;
  1487. X    return r;
  1488. X}
  1489. X
  1490. X/*
  1491. X * This allocates a Node_line_range node with defined condpair and
  1492. X * zeroes the trigger word to avoid the temptation of assuming that calling
  1493. X * 'node( foo, Node_line_range, 0)' will properly initialize 'triggered'. 
  1494. X */
  1495. X/* Otherwise like node() */
  1496. Xstatic NODE *
  1497. Xmkrangenode(cpair)
  1498. XNODE *cpair;
  1499. X{
  1500. X    register NODE *r;
  1501. X
  1502. X    r = newnode(Node_line_range);
  1503. X    r->condpair = cpair;
  1504. X    r->triggered = 0;
  1505. X    return r;
  1506. X}
  1507. X
  1508. X/* Build a for loop */
  1509. Xstatic NODE *
  1510. Xmake_for_loop(init, cond, incr)
  1511. XNODE *init, *cond, *incr;
  1512. X{
  1513. X    register FOR_LOOP_HEADER *r;
  1514. X    NODE *n;
  1515. X
  1516. X    emalloc(r, FOR_LOOP_HEADER *, sizeof(FOR_LOOP_HEADER), "make_for_loop");
  1517. X    n = newnode(Node_illegal);
  1518. X    r->init = init;
  1519. X    r->cond = cond;
  1520. X    r->incr = incr;
  1521. X    n->sub.nodep.r.hd = r;
  1522. X    return n;
  1523. X}
  1524. X
  1525. X/*
  1526. X * Install a name in the hash table specified, even if it is already there.
  1527. X * Name stops with first non alphanumeric. Caller must check against
  1528. X * redefinition if that is desired. 
  1529. X */
  1530. XNODE *
  1531. Xinstall(table, name, value)
  1532. XNODE **table;
  1533. Xchar *name;
  1534. XNODE *value;
  1535. X{
  1536. X    register NODE *hp;
  1537. X    register int len, bucket;
  1538. X    register char *p;
  1539. X
  1540. X    len = 0;
  1541. X    p = name;
  1542. X    while (is_identchar(*p))
  1543. X        p++;
  1544. X    len = p - name;
  1545. X
  1546. X    hp = newnode(Node_hashnode);
  1547. X    bucket = hashf(name, len, HASHSIZE);
  1548. X    hp->hnext = table[bucket];
  1549. X    table[bucket] = hp;
  1550. X    hp->hlength = len;
  1551. X    hp->hvalue = value;
  1552. X    emalloc(hp->hname, char *, len + 1, "install");
  1553. X    memcpy(hp->hname, name, len);
  1554. X    hp->hname[len] = '\0';
  1555. X    return hp->hvalue;
  1556. X}
  1557. X
  1558. X/*
  1559. X * find the most recent hash node for name name (ending with first
  1560. X * non-identifier char) installed by install 
  1561. X */
  1562. XNODE *
  1563. Xlookup(table, name)
  1564. XNODE **table;
  1565. Xchar *name;
  1566. X{
  1567. X    register char *bp;
  1568. X    register NODE *bucket;
  1569. X    register int len;
  1570. X
  1571. X    for (bp = name; is_identchar(*bp); bp++)
  1572. X        ;
  1573. X    len = bp - name;
  1574. X    bucket = table[hashf(name, len, HASHSIZE)];
  1575. X    while (bucket) {
  1576. X        if (bucket->hlength == len && STREQN(bucket->hname, name, len))
  1577. X            return bucket->hvalue;
  1578. X        bucket = bucket->hnext;
  1579. X    }
  1580. X    return NULL;
  1581. X}
  1582. X
  1583. X#define HASHSTEP(old, c) ((old << 1) + c)
  1584. X#define MAKE_POS(v) (v & ~0x80000000)    /* make number positive */
  1585. X
  1586. X/*
  1587. X * return hash function on name.
  1588. X */
  1589. Xstatic int
  1590. Xhashf(name, len, hashsize)
  1591. Xregister char *name;
  1592. Xregister int len;
  1593. Xint hashsize;
  1594. X{
  1595. X    register int r = 0;
  1596. X
  1597. X    while (len--)
  1598. X        r = HASHSTEP(r, *name++);
  1599. X
  1600. X    r = MAKE_POS(r) % hashsize;
  1601. X    return r;
  1602. X}
  1603. X
  1604. X/*
  1605. X * Add new to the rightmost branch of LIST.  This uses n^2 time, so we make
  1606. X * a simple attempt at optimizing it.
  1607. X */
  1608. Xstatic NODE *
  1609. Xappend_right(list, new)
  1610. XNODE *list, *new;
  1611. X
  1612. X{
  1613. X    register NODE *oldlist;
  1614. X    static NODE *savefront = NULL, *savetail = NULL;
  1615. X
  1616. X    oldlist = list;
  1617. X    if (savefront == oldlist) {
  1618. X        savetail = savetail->rnode = new;
  1619. X        return oldlist;
  1620. X    } else
  1621. X        savefront = oldlist;
  1622. X    while (list->rnode != NULL)
  1623. X        list = list->rnode;
  1624. X    savetail = list->rnode = new;
  1625. X    return oldlist;
  1626. X}
  1627. X
  1628. X/*
  1629. X * check if name is already installed;  if so, it had better have Null value,
  1630. X * in which case def is added as the value. Otherwise, install name with def
  1631. X * as value. 
  1632. X */
  1633. Xstatic void
  1634. Xfunc_install(params, def)
  1635. XNODE *params;
  1636. XNODE *def;
  1637. X{
  1638. X    NODE *r;
  1639. X
  1640. X    pop_params(params->rnode);
  1641. X    pop_var(params, 0);
  1642. X    r = lookup(variables, params->param);
  1643. X    if (r != NULL) {
  1644. X        fatal("function name `%s' previously defined", params->param);
  1645. X    } else
  1646. X        (void) install(variables, params->param,
  1647. X            node(params, Node_func, def));
  1648. X}
  1649. X
  1650. Xstatic void
  1651. Xpop_var(np, freeit)
  1652. XNODE *np;
  1653. Xint freeit;
  1654. X{
  1655. X    register char *bp;
  1656. X    register NODE *bucket, **save;
  1657. X    register int len;
  1658. X    char *name;
  1659. X
  1660. X    name = np->param;
  1661. X    for (bp = name; is_identchar(*bp); bp++)
  1662. X        ;
  1663. X    len = bp - name;
  1664. X    save = &(variables[hashf(name, len, HASHSIZE)]);
  1665. X    for (bucket = *save; bucket; bucket = bucket->hnext) {
  1666. X        if (len == bucket->hlength && STREQN(bucket->hname, name, len)) {
  1667. X            *save = bucket->hnext;
  1668. X            freenode(bucket);
  1669. X            free(bucket->hname);
  1670. X            if (freeit)
  1671. X                free(np->param);
  1672. X            return;
  1673. X        }
  1674. X        save = &(bucket->hnext);
  1675. X    }
  1676. X}
  1677. X
  1678. Xstatic void
  1679. Xpop_params(params)
  1680. XNODE *params;
  1681. X{
  1682. X    register NODE *np;
  1683. X
  1684. X    for (np = params; np != NULL; np = np->rnode)
  1685. X        pop_var(np, 1);
  1686. X}
  1687. X
  1688. Xstatic NODE *
  1689. Xmake_param(name)
  1690. Xchar *name;
  1691. X{
  1692. X    NODE *r;
  1693. X
  1694. X    r = newnode(Node_param_list);
  1695. X    r->param = name;
  1696. X    r->rnode = NULL;
  1697. X    r->param_cnt = param_counter++;
  1698. X    return (install(variables, name, r));
  1699. X}
  1700. X
  1701. X/* Name points to a variable name.  Make sure its in the symbol table */
  1702. XNODE *
  1703. Xvariable(name)
  1704. Xchar *name;
  1705. X{
  1706. X    register NODE *r;
  1707. X
  1708. X    if ((r = lookup(variables, name)) == NULL)
  1709. X        r = install(variables, name,
  1710. X            node(Nnull_string, Node_var, (NODE *) NULL));
  1711. X    return r;
  1712. X}
  1713. END_OF_FILE
  1714.   if test 37017 -ne `wc -c <'./awk.y'`; then
  1715.     echo shar: \"'./awk.y'\" unpacked with wrong size!
  1716.   fi
  1717.   # end of './awk.y'
  1718. fi
  1719. if test -f './missing.d/memset.c' -a "${1}" != "-c" ; then 
  1720.   echo shar: Will not clobber existing file \"'./missing.d/memset.c'\"
  1721. else
  1722.   echo shar: Extracting \"'./missing.d/memset.c'\" \(261 characters\)
  1723.   sed "s/^X//" >'./missing.d/memset.c' <<'END_OF_FILE'
  1724. X/*
  1725. X * memset --- initialize memory
  1726. X *
  1727. X * We supply this routine for those systems that aren't standard yet.
  1728. X */
  1729. X
  1730. Xchar *
  1731. Xmemset (dest, val, l)
  1732. Xregister char *dest, val;
  1733. Xregister int l;
  1734. X{
  1735. X    register char *ret = dest;
  1736. X
  1737. X    while (l--)
  1738. X        *dest++ = val;
  1739. X
  1740. X    return ret;
  1741. X}
  1742. END_OF_FILE
  1743.   if test 261 -ne `wc -c <'./missing.d/memset.c'`; then
  1744.     echo shar: \"'./missing.d/memset.c'\" unpacked with wrong size!
  1745.   fi
  1746.   # end of './missing.d/memset.c'
  1747. fi
  1748. if test -f './missing.d/random.c' -a "${1}" != "-c" ; then 
  1749.   echo shar: Will not clobber existing file \"'./missing.d/random.c'\"
  1750. else
  1751.   echo shar: Extracting \"'./missing.d/random.c'\" \(12785 characters\)
  1752.   sed "s/^X//" >'./missing.d/random.c' <<'END_OF_FILE'
  1753. X/*
  1754. X * Copyright (c) 1983 Regents of the University of California.
  1755. X * All rights reserved.
  1756. X *
  1757. X * Redistribution and use in source and binary forms are permitted
  1758. X * provided that the above copyright notice and this paragraph are
  1759. X * duplicated in all such forms and that any documentation,
  1760. X * advertising materials, and other materials related to such
  1761. X * distribution and use acknowledge that the software was developed
  1762. X * by the University of California, Berkeley.  The name of the
  1763. X * University may not be used to endorse or promote products derived
  1764. X * from this software without specific prior written permission.
  1765. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  1766. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  1767. X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  1768. X */
  1769. X
  1770. X#if defined(LIBC_SCCS) && !defined(lint)
  1771. Xstatic char sccsid[] = "@(#)random.c    5.5 (Berkeley) 7/6/88";
  1772. X#endif /* LIBC_SCCS and not lint */
  1773. X
  1774. X#include <stdio.h>
  1775. X
  1776. X/*
  1777. X * random.c:
  1778. X * An improved random number generation package.  In addition to the standard
  1779. X * rand()/srand() like interface, this package also has a special state info
  1780. X * interface.  The initstate() routine is called with a seed, an array of
  1781. X * bytes, and a count of how many bytes are being passed in; this array is then
  1782. X * initialized to contain information for random number generation with that
  1783. X * much state information.  Good sizes for the amount of state information are
  1784. X * 32, 64, 128, and 256 bytes.  The state can be switched by calling the
  1785. X * setstate() routine with the same array as was initiallized with initstate().
  1786. X * By default, the package runs with 128 bytes of state information and
  1787. X * generates far better random numbers than a linear congruential generator.
  1788. X * If the amount of state information is less than 32 bytes, a simple linear
  1789. X * congruential R.N.G. is used.
  1790. X * Internally, the state information is treated as an array of longs; the
  1791. X * zeroeth element of the array is the type of R.N.G. being used (small
  1792. X * integer); the remainder of the array is the state information for the
  1793. X * R.N.G.  Thus, 32 bytes of state information will give 7 longs worth of
  1794. X * state information, which will allow a degree seven polynomial.  (Note: the
  1795. X * zeroeth word of state information also has some other information stored
  1796. X * in it -- see setstate() for details).
  1797. X * The random number generation technique is a linear feedback shift register
  1798. X * approach, employing trinomials (since there are fewer terms to sum up that
  1799. X * way).  In this approach, the least significant bit of all the numbers in
  1800. X * the state table will act as a linear feedback shift register, and will have
  1801. X * period 2^deg - 1 (where deg is the degree of the polynomial being used,
  1802. X * assuming that the polynomial is irreducible and primitive).  The higher
  1803. X * order bits will have longer periods, since their values are also influenced
  1804. X * by pseudo-random carries out of the lower bits.  The total period of the
  1805. X * generator is approximately deg*(2**deg - 1); thus doubling the amount of
  1806. X * state information has a vast influence on the period of the generator.
  1807. X * Note: the deg*(2**deg - 1) is an approximation only good for large deg,
  1808. X * when the period of the shift register is the dominant factor.  With deg
  1809. X * equal to seven, the period is actually much longer than the 7*(2**7 - 1)
  1810. X * predicted by this formula.
  1811. X */
  1812. X
  1813. X
  1814. X
  1815. X/*
  1816. X * For each of the currently supported random number generators, we have a
  1817. X * break value on the amount of state information (you need at least this
  1818. X * many bytes of state info to support this random number generator), a degree
  1819. X * for the polynomial (actually a trinomial) that the R.N.G. is based on, and
  1820. X * the separation between the two lower order coefficients of the trinomial.
  1821. X */
  1822. X
  1823. X#define        TYPE_0        0        /* linear congruential */
  1824. X#define        BREAK_0        8
  1825. X#define        DEG_0        0
  1826. X#define        SEP_0        0
  1827. X
  1828. X#define        TYPE_1        1        /* x**7 + x**3 + 1 */
  1829. X#define        BREAK_1        32
  1830. X#define        DEG_1        7
  1831. X#define        SEP_1        3
  1832. X
  1833. X#define        TYPE_2        2        /* x**15 + x + 1 */
  1834. X#define        BREAK_2        64
  1835. X#define        DEG_2        15
  1836. X#define        SEP_2        1
  1837. X
  1838. X#define        TYPE_3        3        /* x**31 + x**3 + 1 */
  1839. X#define        BREAK_3        128
  1840. X#define        DEG_3        31
  1841. X#define        SEP_3        3
  1842. X
  1843. X#define        TYPE_4        4        /* x**63 + x + 1 */
  1844. X#define        BREAK_4        256
  1845. X#define        DEG_4        63
  1846. X#define        SEP_4        1
  1847. X
  1848. X
  1849. X/*
  1850. X * Array versions of the above information to make code run faster -- relies
  1851. X * on fact that TYPE_i == i.
  1852. X */
  1853. X
  1854. X#define        MAX_TYPES    5        /* max number of types above */
  1855. X
  1856. Xstatic  int        degrees[ MAX_TYPES ]    = { DEG_0, DEG_1, DEG_2,
  1857. X                                DEG_3, DEG_4 };
  1858. X
  1859. Xstatic  int        seps[ MAX_TYPES ]    = { SEP_0, SEP_1, SEP_2,
  1860. X                                SEP_3, SEP_4 };
  1861. X
  1862. X
  1863. X
  1864. X/*
  1865. X * Initially, everything is set up as if from :
  1866. X *        initstate( 1, &randtbl, 128 );
  1867. X * Note that this initialization takes advantage of the fact that srandom()
  1868. X * advances the front and rear pointers 10*rand_deg times, and hence the
  1869. X * rear pointer which starts at 0 will also end up at zero; thus the zeroeth
  1870. X * element of the state information, which contains info about the current
  1871. X * position of the rear pointer is just
  1872. X *    MAX_TYPES*(rptr - state) + TYPE_3 == TYPE_3.
  1873. X */
  1874. X
  1875. Xstatic  long        randtbl[ DEG_3 + 1 ]    = { TYPE_3,
  1876. X                0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342,
  1877. X                0xde3b81e0, 0xdf0a6fb5, 0xf103bc02, 0x48f340fb,
  1878. X                0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd,
  1879. X                0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86,
  1880. X                0xda672e2a, 0x1588ca88, 0xe369735d, 0x904f35f7,
  1881. X                0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc,
  1882. X                0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b,
  1883. X                    0xf5ad9d0e, 0x8999220b, 0x27fb47b9 };
  1884. X
  1885. X/*
  1886. X * fptr and rptr are two pointers into the state info, a front and a rear
  1887. X * pointer.  These two pointers are always rand_sep places aparts, as they cycle
  1888. X * cyclically through the state information.  (Yes, this does mean we could get
  1889. X * away with just one pointer, but the code for random() is more efficient this
  1890. X * way).  The pointers are left positioned as they would be from the call
  1891. X *            initstate( 1, randtbl, 128 )
  1892. X * (The position of the rear pointer, rptr, is really 0 (as explained above
  1893. X * in the initialization of randtbl) because the state table pointer is set
  1894. X * to point to randtbl[1] (as explained below).
  1895. X */
  1896. X
  1897. Xstatic  long        *fptr            = &randtbl[ SEP_3 + 1 ];
  1898. Xstatic  long        *rptr            = &randtbl[ 1 ];
  1899. X
  1900. X
  1901. X
  1902. X/*
  1903. X * The following things are the pointer to the state information table,
  1904. X * the type of the current generator, the degree of the current polynomial
  1905. X * being used, and the separation between the two pointers.
  1906. X * Note that for efficiency of random(), we remember the first location of
  1907. X * the state information, not the zeroeth.  Hence it is valid to access
  1908. X * state[-1], which is used to store the type of the R.N.G.
  1909. X * Also, we remember the last location, since this is more efficient than
  1910. X * indexing every time to find the address of the last element to see if
  1911. X * the front and rear pointers have wrapped.
  1912. X */
  1913. X
  1914. Xstatic  long        *state            = &randtbl[ 1 ];
  1915. X
  1916. Xstatic  int        rand_type        = TYPE_3;
  1917. Xstatic  int        rand_deg        = DEG_3;
  1918. Xstatic  int        rand_sep        = SEP_3;
  1919. X
  1920. Xstatic  long        *end_ptr        = &randtbl[ DEG_3 + 1 ];
  1921. X
  1922. X
  1923. X
  1924. X/*
  1925. X * srandom:
  1926. X * Initialize the random number generator based on the given seed.  If the
  1927. X * type is the trivial no-state-information type, just remember the seed.
  1928. X * Otherwise, initializes state[] based on the given "seed" via a linear
  1929. X * congruential generator.  Then, the pointers are set to known locations
  1930. X * that are exactly rand_sep places apart.  Lastly, it cycles the state
  1931. X * information a given number of times to get rid of any initial dependencies
  1932. X * introduced by the L.C.R.N.G.
  1933. X * Note that the initialization of randtbl[] for default usage relies on
  1934. X * values produced by this routine.
  1935. X */
  1936. X
  1937. Xsrandom( x )
  1938. X
  1939. X    unsigned        x;
  1940. X{
  1941. X        register  int        i, j;
  1942. X    long random();
  1943. X
  1944. X    if(  rand_type  ==  TYPE_0  )  {
  1945. X        state[ 0 ] = x;
  1946. X    }
  1947. X    else  {
  1948. X        j = 1;
  1949. X        state[ 0 ] = x;
  1950. X        for( i = 1; i < rand_deg; i++ )  {
  1951. X        state[i] = 1103515245*state[i - 1] + 12345;
  1952. X        }
  1953. X        fptr = &state[ rand_sep ];
  1954. X        rptr = &state[ 0 ];
  1955. X        for( i = 0; i < 10*rand_deg; i++ )  random();
  1956. X    }
  1957. X}
  1958. X
  1959. X
  1960. X
  1961. X/*
  1962. X * initstate:
  1963. X * Initialize the state information in the given array of n bytes for
  1964. X * future random number generation.  Based on the number of bytes we
  1965. X * are given, and the break values for the different R.N.G.'s, we choose
  1966. X * the best (largest) one we can and set things up for it.  srandom() is
  1967. X * then called to initialize the state information.
  1968. X * Note that on return from srandom(), we set state[-1] to be the type
  1969. X * multiplexed with the current value of the rear pointer; this is so
  1970. X * successive calls to initstate() won't lose this information and will
  1971. X * be able to restart with setstate().
  1972. X * Note: the first thing we do is save the current state, if any, just like
  1973. X * setstate() so that it doesn't matter when initstate is called.
  1974. X * Returns a pointer to the old state.
  1975. X */
  1976. X
  1977. Xchar  *
  1978. Xinitstate( seed, arg_state, n )
  1979. X
  1980. X    unsigned        seed;            /* seed for R. N. G. */
  1981. X    char        *arg_state;        /* pointer to state array */
  1982. X    int            n;            /* # bytes of state info */
  1983. X{
  1984. X    register  char        *ostate        = (char *)( &state[ -1 ] );
  1985. X
  1986. X    if(  rand_type  ==  TYPE_0  )  state[ -1 ] = rand_type;
  1987. X    else  state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type;
  1988. X    if(  n  <  BREAK_1  )  {
  1989. X        if(  n  <  BREAK_0  )  {
  1990. X        fprintf( stderr, "initstate: not enough state (%d bytes) with which to do jack; ignored.\n", n );
  1991. X        return 0;
  1992. X        }
  1993. X        rand_type = TYPE_0;
  1994. X        rand_deg = DEG_0;
  1995. X        rand_sep = SEP_0;
  1996. X    }
  1997. X    else  {
  1998. X        if(  n  <  BREAK_2  )  {
  1999. X        rand_type = TYPE_1;
  2000. X        rand_deg = DEG_1;
  2001. X        rand_sep = SEP_1;
  2002. X        }
  2003. X        else  {
  2004. X        if(  n  <  BREAK_3  )  {
  2005. X            rand_type = TYPE_2;
  2006. X            rand_deg = DEG_2;
  2007. X            rand_sep = SEP_2;
  2008. X        }
  2009. X        else  {
  2010. X            if(  n  <  BREAK_4  )  {
  2011. X            rand_type = TYPE_3;
  2012. X            rand_deg = DEG_3;
  2013. X            rand_sep = SEP_3;
  2014. X            }
  2015. X            else  {
  2016. X            rand_type = TYPE_4;
  2017. X            rand_deg = DEG_4;
  2018. X            rand_sep = SEP_4;
  2019. X            }
  2020. X        }
  2021. X        }
  2022. X    }
  2023. X    state = &(  ( (long *)arg_state )[1]  );    /* first location */
  2024. X    end_ptr = &state[ rand_deg ];    /* must set end_ptr before srandom */
  2025. X    srandom( seed );
  2026. X    if(  rand_type  ==  TYPE_0  )  state[ -1 ] = rand_type;
  2027. X    else  state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type;
  2028. X    return( ostate );
  2029. X}
  2030. X
  2031. X
  2032. X
  2033. X/*
  2034. X * setstate:
  2035. X * Restore the state from the given state array.
  2036. X * Note: it is important that we also remember the locations of the pointers
  2037. X * in the current state information, and restore the locations of the pointers
  2038. X * from the old state information.  This is done by multiplexing the pointer
  2039. X * location into the zeroeth word of the state information.
  2040. X * Note that due to the order in which things are done, it is OK to call
  2041. X * setstate() with the same state as the current state.
  2042. X * Returns a pointer to the old state information.
  2043. X */
  2044. X
  2045. Xchar  *
  2046. Xsetstate( arg_state )
  2047. X
  2048. X    char        *arg_state;
  2049. X{
  2050. X    register  long        *new_state    = (long *)arg_state;
  2051. X    register  int        type        = new_state[0]%MAX_TYPES;
  2052. X    register  int        rear        = new_state[0]/MAX_TYPES;
  2053. X    char            *ostate        = (char *)( &state[ -1 ] );
  2054. X
  2055. X    if(  rand_type  ==  TYPE_0  )  state[ -1 ] = rand_type;
  2056. X    else  state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type;
  2057. X    switch(  type  )  {
  2058. X        case  TYPE_0:
  2059. X        case  TYPE_1:
  2060. X        case  TYPE_2:
  2061. X        case  TYPE_3:
  2062. X        case  TYPE_4:
  2063. X        rand_type = type;
  2064. X        rand_deg = degrees[ type ];
  2065. X        rand_sep = seps[ type ];
  2066. X        break;
  2067. X
  2068. X        default:
  2069. X        fprintf( stderr, "setstate: state info has been munged; not changed.\n" );
  2070. X    }
  2071. X    state = &new_state[ 1 ];
  2072. X    if(  rand_type  !=  TYPE_0  )  {
  2073. X        rptr = &state[ rear ];
  2074. X        fptr = &state[ (rear + rand_sep)%rand_deg ];
  2075. X    }
  2076. X    end_ptr = &state[ rand_deg ];        /* set end_ptr too */
  2077. X    return( ostate );
  2078. X}
  2079. X
  2080. X
  2081. X
  2082. X/*
  2083. X * random:
  2084. X * If we are using the trivial TYPE_0 R.N.G., just do the old linear
  2085. X * congruential bit.  Otherwise, we do our fancy trinomial stuff, which is the
  2086. X * same in all ther other cases due to all the global variables that have been
  2087. X * set up.  The basic operation is to add the number at the rear pointer into
  2088. X * the one at the front pointer.  Then both pointers are advanced to the next
  2089. X * location cyclically in the table.  The value returned is the sum generated,
  2090. X * reduced to 31 bits by throwing away the "least random" low bit.
  2091. X * Note: the code takes advantage of the fact that both the front and
  2092. X * rear pointers can't wrap on the same call by not testing the rear
  2093. X * pointer if the front one has wrapped.
  2094. X * Returns a 31-bit random number.
  2095. X */
  2096. X
  2097. Xlong
  2098. Xrandom()
  2099. X{
  2100. X    long        i;
  2101. X
  2102. X    if(  rand_type  ==  TYPE_0  )  {
  2103. X        i = state[0] = ( state[0]*1103515245 + 12345 )&0x7fffffff;
  2104. X    }
  2105. X    else  {
  2106. X        *fptr += *rptr;
  2107. X        i = (*fptr >> 1)&0x7fffffff;    /* chucking least random bit */
  2108. X        if(  ++fptr  >=  end_ptr  )  {
  2109. X        fptr = state;
  2110. X        ++rptr;
  2111. X        }
  2112. X        else  {
  2113. X        if(  ++rptr  >=  end_ptr  )  rptr = state;
  2114. X        }
  2115. X    }
  2116. X    return( i );
  2117. X}
  2118. END_OF_FILE
  2119.   if test 12785 -ne `wc -c <'./missing.d/random.c'`; then
  2120.     echo shar: \"'./missing.d/random.c'\" unpacked with wrong size!
  2121.   fi
  2122.   # end of './missing.d/random.c'
  2123. fi
  2124. if test -f './pc.d/popen.h' -a "${1}" != "-c" ; then 
  2125.   echo shar: Will not clobber existing file \"'./pc.d/popen.h'\"
  2126. else
  2127.   echo shar: Extracting \"'./pc.d/popen.h'\" \(134 characters\)
  2128.   sed "s/^X//" >'./pc.d/popen.h' <<'END_OF_FILE'
  2129. X/*
  2130. X** popen.h -- prototypes for pipe functions
  2131. X*/
  2132. X#if !defined(FILE)
  2133. X#include <stdio.h>
  2134. X#endif
  2135. Xextern FILE *popen( char *, char * );
  2136. X
  2137. END_OF_FILE
  2138.   if test 134 -ne `wc -c <'./pc.d/popen.h'`; then
  2139.     echo shar: \"'./pc.d/popen.h'\" unpacked with wrong size!
  2140.   fi
  2141.   # end of './pc.d/popen.h'
  2142. fi
  2143. echo shar: End of archive 10 \(of 16\).
  2144. cp /dev/null ark10isdone
  2145. MISSING=""
  2146. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do
  2147.     if test ! -f ark${I}isdone ; then
  2148.     MISSING="${MISSING} ${I}"
  2149.     fi
  2150. done
  2151. if test "${MISSING}" = "" ; then
  2152.     echo You have unpacked all 16 archives.
  2153.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2154. else
  2155.     echo You still must unpack the following archives:
  2156.     echo "        " ${MISSING}
  2157. fi
  2158. exit 0
  2159. exit 0 # Just in case...
  2160.